home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / opengl / x+opengl / paperplane.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  11.9 KB  |  373 lines

  1. /*
  2.  * Copyright 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /* $Revision: 1.9 $ */
  18. /*
  19.  * paperplane can be compiled to use a "single visual" for the entire window
  20.  * hierarchy and render OpenGL into a standard Motif drawing area widget:
  21.  *
  22.  *  cc -o sv_paperplane paperplane.c -DnoGLwidget -lGL -lXm -lXt -lX11 -lm
  23.  *
  24.  * Or paperplane can be compiled to use the default visual for most of
  25.  * the window hierarchy but render OpenGL into a special "OpenGL widget":
  26.  *
  27.  *  cc -o glw_paperplane paperplane.c -lGLw -lGL -lXm -lXt -lX11 -lm 
  28.  */
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <unistd.h>
  32. #include <math.h>
  33. #include <Xm/MainW.h>
  34. #include <Xm/RowColumn.h>
  35. #include <Xm/PushB.h>
  36. #include <Xm/ToggleB.h>
  37. #include <Xm/CascadeB.h>
  38. #include <Xm/Frame.h>
  39. #ifdef noGLwidget
  40. #include <Xm/DrawingA.h>    /* Motif drawing area widget */
  41. #else
  42. #ifdef noMotifGLwidget
  43. #include <GL/GLwDrawA.h>    /* pure Xt OpenGL drawing area widget */
  44. #else
  45. #include <GL/GLwMDrawA.h>    /* Motif OpenGL drawing area widget */
  46. #endif
  47. #endif
  48. #include <X11/keysym.h>
  49. #include <GL/gl.h>
  50. #include <GL/glu.h>
  51. #include <GL/glx.h>
  52.  
  53. static int dblBuf[] = {
  54.     GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16,
  55.     GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
  56.     None
  57. };
  58. static int *snglBuf = &dblBuf[1];
  59. static String   fallbackResources[] = {
  60. #ifdef IRIX_5_2_or_higher
  61.     "*sgiMode: true",        /* try to enable IRIX 5.2+ look & feel */
  62.     "*useSchemes: all",        /* and SGI schemes */
  63. #endif
  64.     "*title: OpenGL paper plane demo",
  65.     "*glxarea*width: 300", "*glxarea*height: 300", NULL
  66. };
  67. Display     *dpy;
  68. GLboolean    doubleBuffer = GL_TRUE, moving = GL_FALSE, made_current = GL_FALSE;
  69. XtAppContext app;
  70. XtWorkProcId workId = 0;
  71. Widget       toplevel, mainw, menubar, menupane, btn, cascade, frame, glxarea;
  72. GLXContext   cx;
  73. XVisualInfo *vi;
  74. #ifdef noGLwidget
  75. Colormap     cmap;
  76. #endif
  77. Arg          menuPaneArgs[1], args[1];
  78.  
  79. #define MAX_PLANES 15
  80.  
  81. struct {
  82.     float           speed;    /* zero speed means not flying */
  83.     GLfloat         red, green, blue;
  84.     float           theta;
  85.     float           x, y, z, angle;
  86. } planes[MAX_PLANES];
  87.  
  88. #define v3f glVertex3f /* v3f was the short IRIS GL name for glVertex3f */
  89.  
  90. void draw(Widget w)
  91. {
  92.     GLfloat         red, green, blue;
  93.     int             i;
  94.  
  95.     glClear(GL_DEPTH_BUFFER_BIT);
  96.     /* paint black to blue smooth shaded polygon for background */
  97.     glDisable(GL_DEPTH_TEST);
  98.     glShadeModel(GL_SMOOTH);
  99.     glBegin(GL_POLYGON);
  100.         glColor3f(0.0, 0.0, 0.0);
  101.         v3f(-20, 20, -19); v3f(20, 20, -19);
  102.         glColor3f(0.0, 0.0, 1.0);
  103.         v3f(20, -20, -19); v3f(-20, -20, -19);
  104.     glEnd();
  105.     /* paint planes */
  106.     glEnable(GL_DEPTH_TEST);
  107.     glShadeModel(GL_FLAT);
  108.     for (i = 0; i < MAX_PLANES; i++)
  109.     if (planes[i].speed != 0.0) {
  110.         glPushMatrix();
  111.             glTranslatef(planes[i].x, planes[i].y, planes[i].z);
  112.             glRotatef(290.0, 1.0, 0.0, 0.0);
  113.             glRotatef(planes[i].angle, 0.0, 0.0, 1.0);
  114.             glScalef(1.0 / 3.0, 1.0 / 4.0, 1.0 / 4.0);
  115.             glTranslatef(0.0, -4.0, -1.5);
  116.             glBegin(GL_TRIANGLE_STRIP);
  117.                 /* left wing */
  118.                 v3f(-7.0, 0.0, 2.0); v3f(-1.0, 0.0, 3.0);
  119.                 glColor3f(red = planes[i].red, green = planes[i].green,
  120.                           blue = planes[i].blue);
  121.                 v3f(-1.0, 7.0, 3.0);
  122.                 /* left side */
  123.                 glColor3f(0.6 * red, 0.6 * green, 0.6 * blue);
  124.                 v3f(0.0, 0.0, 0.0); v3f(0.0, 8.0, 0.0);
  125.                 /* right side */
  126.                 v3f(1.0, 0.0, 3.0); v3f(1.0, 7.0, 3.0);
  127.                 /* final tip of right wing */
  128.                 glColor3f(red, green, blue);
  129.                 v3f(7.0, 0.0, 2.0);
  130.             glEnd();
  131.         glPopMatrix();
  132.     }
  133.     if (doubleBuffer) glXSwapBuffers(dpy, XtWindow(w));
  134.     if(!glXIsDirect(dpy, cx))
  135.         glFinish(); /* avoid indirect rendering latency from queuing */
  136. #ifdef DEBUG
  137.     { /* for help debugging, report any OpenGL errors that occur per frame */
  138.         GLenum error;
  139.         while((error = glGetError()) != GL_NO_ERROR)
  140.             fprintf(stderr, "GL error: %s\n", gluErrorString(error));
  141.     }
  142. #endif
  143. }
  144.  
  145. void tick_per_plane(int i)
  146. {
  147.     float theta = planes[i].theta += planes[i].speed;
  148.     planes[i].z = -9 + 4 * cos(theta);
  149.     planes[i].x = 4 * sin(2 * theta);
  150.     planes[i].y = sin(theta / 3.4) * 3;
  151.     planes[i].angle = ((atan(2.0) + M_PI_2) * sin(theta) - M_PI_2) * 180 / M_PI;
  152.     if (planes[i].speed < 0.0) planes[i].angle += 180;
  153. }
  154.  
  155. void add_plane(void)
  156. {
  157.     int i;
  158.  
  159.     for (i = 0; i < MAX_PLANES; i++)
  160.     if (planes[i].speed == 0) {
  161.  
  162. #define SET_COLOR(r,g,b) \
  163.     planes[i].red=r; planes[i].green=g; planes[i].blue=b; break;
  164.  
  165.             switch (random() % 6) {
  166.             case 0: SET_COLOR(1.0, 0.0, 0.0); /* red */
  167.             case 1: SET_COLOR(1.0, 1.0, 1.0); /* white */
  168.             case 2: SET_COLOR(0.0, 1.0, 0.0); /* green */
  169.             case 3: SET_COLOR(1.0, 0.0, 1.0); /* magenta */
  170.             case 4: SET_COLOR(1.0, 1.0, 0.0); /* yellow */
  171.             case 5: SET_COLOR(0.0, 1.0, 1.0); /* cyan */
  172.             }
  173.             planes[i].speed = (random() % 20) * 0.001 + 0.02;
  174.             if (random() & 0x1) planes[i].speed *= -1;
  175.         planes[i].theta = ((float) (random() % 257)) * 0.1111;
  176.         tick_per_plane(i);
  177.         if (!moving) draw(glxarea);
  178.         return;
  179.     }
  180.     XBell(dpy, 100); /* can't add any more planes */
  181. }
  182.  
  183. void remove_plane(void)
  184. {
  185.     int             i;
  186.  
  187.     for (i = MAX_PLANES - 1; i >= 0; i--)
  188.     if (planes[i].speed != 0) {
  189.         planes[i].speed = 0;
  190.         if (!moving) draw(glxarea);
  191.         return;
  192.     }
  193.     XBell(dpy, 100); /* no more planes to remove */
  194. }
  195.  
  196. void resize(Widget w, XtPointer data, XtPointer callData)
  197. {
  198.     Dimension       width, height;
  199.  
  200.     if(made_current) {
  201.     XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
  202.     glViewport(0, 0, (GLint) width, (GLint) height);
  203.     }
  204. }
  205.  
  206. void tick(void)
  207. {
  208.     int i;
  209.  
  210.     for (i = 0; i < MAX_PLANES; i++)
  211.     if (planes[i].speed != 0.0) tick_per_plane(i);
  212. }
  213.  
  214. Boolean animate(XtPointer data)
  215. {
  216.     tick();
  217.     draw(glxarea);
  218.     return False;        /* leave work proc active */
  219. }
  220.  
  221. void toggle(void)
  222. {
  223.     moving = !moving; /* toggle */
  224.     if (moving)
  225.     workId = XtAppAddWorkProc(app, animate, NULL);
  226.     else
  227.     XtRemoveWorkProc(workId);
  228. }
  229.  
  230. void quit(Widget w, XtPointer data, XtPointer callData)
  231. {
  232.     exit(0);
  233. }
  234.  
  235. void input(Widget w, XtPointer data, XtPointer callData)
  236. {
  237.     XmDrawingAreaCallbackStruct *cd = (XmDrawingAreaCallbackStruct *) callData;
  238.     char            buf[1];
  239.     KeySym          keysym;
  240.     int             rc;
  241.  
  242.     if(cd->event->type == KeyPress)
  243.     if(XLookupString((XKeyEvent *) cd->event, buf, 1, &keysym, NULL) == 1)
  244.         switch (keysym) {
  245.         case XK_space:
  246.             if (!moving) { /* advance one frame if not in motion */
  247.                 tick();
  248.             draw(w);
  249.             }
  250.             break;
  251.         case XK_Escape:
  252.             exit(0);
  253.         }
  254. }
  255.  
  256. void map_state_changed(Widget w, XtPointer data, XEvent * event, Boolean * cont)
  257. {
  258.     switch (event->type) {
  259.     case MapNotify:
  260.     if (moving && workId != 0) workId = XtAppAddWorkProc(app, animate, NULL);
  261.     break;
  262.     case UnmapNotify:
  263.     if (moving) XtRemoveWorkProc(workId);
  264.     break;
  265.     }
  266. }
  267.  
  268. main(int argc, char *argv[])
  269. {
  270.     toplevel = XtAppInitialize(&app, "Paperplane", NULL, 0, &argc, argv,
  271.                    fallbackResources, NULL, 0);
  272.     dpy = XtDisplay(toplevel);
  273.     /* find an OpenGL-capable RGB visual with depth buffer */
  274.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf);
  275.     if (vi == NULL) {
  276.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf);
  277.     if (vi == NULL)
  278.         XtAppError(app, "no RGB visual with depth buffer");
  279.     doubleBuffer = GL_FALSE;
  280.     }
  281.     /* create an OpenGL rendering context */
  282.     cx = glXCreateContext(dpy, vi, /* no display list sharing */ None,
  283.         /* favor direct */ GL_TRUE);
  284.     if (cx == NULL)
  285.     XtAppError(app, "could not create rendering context");
  286.     /* create an X colormap since probably not using default visual */
  287. #ifdef noGLwidget
  288.     cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
  289.         vi->visual, AllocNone);
  290.     /*
  291.      * Establish the visual, depth, and colormap of the toplevel
  292.      * widget _before_ the widget is realized.
  293.      */
  294.     XtVaSetValues(toplevel, XtNvisual, vi->visual, XtNdepth, vi->depth,
  295.           XtNcolormap, cmap, NULL);
  296. #endif
  297.     XtAddEventHandler(toplevel, StructureNotifyMask, False,
  298.                       map_state_changed, NULL);
  299.     mainw = XmCreateMainWindow(toplevel, "mainw", NULL, 0);
  300.     XtManageChild(mainw);
  301.     /* create menu bar */
  302.     menubar = XmCreateMenuBar(mainw, "menubar", NULL, 0);
  303.     XtManageChild(menubar);
  304. #ifdef noGLwidget
  305.     /* Hack around Xt's unfortunate default visual inheritance. */
  306.     XtSetArg(menuPaneArgs[0], XmNvisual, vi->visual);
  307.     menupane = XmCreatePulldownMenu(menubar, "menupane", menuPaneArgs, 1);
  308. #else
  309.     menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0);
  310. #endif
  311.     btn = XmCreatePushButton(menupane, "Quit", NULL, 0);
  312.     XtAddCallback(btn, XmNactivateCallback, quit, NULL);
  313.     XtManageChild(btn);
  314.     XtSetArg(args[0], XmNsubMenuId, menupane);
  315.     cascade = XmCreateCascadeButton(menubar, "File", args, 1);
  316.     XtManageChild(cascade);
  317. #ifdef noGLwidget
  318.     menupane = XmCreatePulldownMenu(menubar, "menupane", menuPaneArgs, 1);
  319. #else
  320.     menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0);
  321. #endif
  322.     btn = XmCreateToggleButton(menupane, "Motion", NULL, 0);
  323.     XtAddCallback(btn, XmNvalueChangedCallback, (XtCallbackProc)toggle, NULL);
  324.     XtManageChild(btn);
  325.     btn = XmCreatePushButton(menupane, "Add plane", NULL, 0);
  326.     XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)add_plane, NULL);
  327.     XtManageChild(btn);
  328.     btn = XmCreatePushButton(menupane, "Remove plane", NULL, 0);
  329.     XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)remove_plane, NULL);
  330.     XtManageChild(btn);
  331.     XtSetArg(args[0], XmNsubMenuId, menupane);
  332.     cascade = XmCreateCascadeButton(menubar, "Planes", args, 1);
  333.     XtManageChild(cascade);
  334.     /* create framed drawing area for OpenGL rendering */
  335.     frame = XmCreateFrame(mainw, "frame", NULL, 0);
  336.     XtManageChild(frame);
  337. #ifdef noGLwidget
  338.     glxarea = XtVaCreateManagedWidget("glxarea", xmDrawingAreaWidgetClass,
  339.                                       frame, NULL);
  340. #else
  341. #ifdef noMotifGLwidget
  342.     /* notice glwDrawingAreaWidgetClass lacks an 'M' */
  343.     glxarea = XtVaCreateManagedWidget("glxarea", glwDrawingAreaWidgetClass,
  344. #else
  345.     glxarea = XtVaCreateManagedWidget("glxarea", glwMDrawingAreaWidgetClass,
  346. #endif
  347.                       frame, GLwNvisualInfo, vi, NULL);
  348. #endif
  349.     XtAddCallback(glxarea, XmNexposeCallback, (XtCallbackProc)draw, NULL);
  350.     XtAddCallback(glxarea, XmNresizeCallback, resize, NULL);
  351.     XtAddCallback(glxarea, XmNinputCallback, input, NULL);
  352.     /* set up application's window layout */
  353.     XmMainWindowSetAreas(mainw, menubar, NULL, NULL, NULL, frame);
  354.     XtRealizeWidget(toplevel);
  355.     /*
  356.      * Once widget is realized (ie, associated with a created X window), we
  357.      * can bind the OpenGL rendering context to the window.
  358.      */
  359.     glXMakeCurrent(dpy, XtWindow(glxarea), cx);
  360.     made_current = GL_TRUE;
  361.     /* setup OpenGL state */
  362.     glClearDepth(1.0);
  363.     glClearColor(0.0, 0.0, 0.0, 0.0);
  364.     glMatrixMode(GL_PROJECTION);
  365.     glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 20);
  366.     glMatrixMode(GL_MODELVIEW);
  367.     /* add three initial random planes */
  368.     srandom(getpid());
  369.     add_plane(); add_plane(); add_plane();
  370.     /* start event processing */
  371.     XtAppMainLoop(app);
  372. }
  373.